import sys
import os
import requests
import logging
from datetime import datetime
from typing import List, Dict, Optional
import time
import urllib.parse

logger = logging.getLogger(__name__)

class FDADataFetcher:
    """Fetch data from openFDA API for device analysis"""
    
    def __init__(self, api_key=None, base_url="https://api.fda.gov"):
        self.base_url = base_url
        self.api_key = api_key
        self.session = requests.Session()
        
        if self.api_key:
            logger.info(f"Using FDA API key (length: {len(self.api_key)})")
        else:
            logger.warning("No FDA API key - using public access")
    
    def _make_request(self, endpoint: str, params: Dict) -> Optional[Dict]:
        """Make API request with error handling"""
        url = f"{self.base_url}{endpoint}"
        
        # 添加API密钥
        if self.api_key:
            params['api_key'] = self.api_key
        
        logger.info(f"Making request to: {url}")
        logger.info(f"Parameters: {params}")
        
        try:
            response = self.session.get(url, params=params, timeout=30)
            
            # 记录响应信息用于调试
            logger.info(f"Response status: {response.status_code}")
            logger.info(f"Response URL: {response.url}")
            
            if response.status_code != 200:
                error_msg = f"HTTP {response.status_code}: {response.text[:200]}"
                logger.error(f"API error: {error_msg}")
                return None
            
            data = response.json()
            
            # 检查是否有错误
            if 'error' in data:
                logger.error(f"API returned error: {data['error']}")
                return None
                
            return data
            
        except requests.exceptions.Timeout:
            logger.error(f"Timeout fetching {endpoint}")
            return None
        except requests.exceptions.RequestException as e:
            logger.error(f"Request error: {str(e)}")
            return None
        except ValueError as e:
            logger.error(f"JSON parsing error: {str(e)}")
            return None
    
    def _build_search_query(self, endpoint: str, product_code: str) -> str:
        """构建正确的查询字符串"""
        # 不同的端点使用不同的字段名
        endpoint_fields = {
            '/device/510k.json': {
                'product_code_field': 'product_code',  # 直接字段
                'date_field': 'decision_date'  # 决策日期
            },
            '/device/event.json': {
                'product_code_field': 'device.product_code',  # 设备产品代码
                'date_field': 'date_received'  # 接收日期
            },
            '/device/recall.json': {
                'product_code_field': 'product_code',  # 直接字段
                'date_field': 'event_date_initiated'  # 事件开始日期
            }
        }
        
        fields = endpoint_fields.get(endpoint, {
            'product_code_field': 'product_code',
            'date_field': 'date_received'
        })
        
        # 构建查询 - 注意: openFDA查询语法很严格
        search_query = f'{fields["product_code_field"]}:"{product_code}"'
        
        # 添加日期范围（如果需要）
        if 'date_field' in fields and fields['date_field']:
            date_query = f'AND+{fields["date_field"]}:["2010-01-01"+TO+"2025-12-31"]'
            search_query = f'{search_query}+{date_query}'
        
        logger.info(f"Built search query for {endpoint}: {search_query}")
        return search_query
    
    def get_510k_records(self, product_code: str = None, limit: int = 10) -> Dict:
        """Fetch latest 510(k) records for a single product code"""
        if not product_code:
            return {'status': 'error', 'message': 'No product code provided'}
        
        # 方法1: 直接搜索产品代码
        search = f'product_code:"{product_code}"'
        
        # 方法2: 使用openfda子字段（更可靠）
        # search = f'openfda.product_code:"{product_code}"'
        
        # 方法3: 最简单的搜索，只按产品代码
        # search = f'product_code:{product_code}'
        
        params = {
            'search': search,
            'sort': 'decision_date:desc',
            'limit': limit
        }
        
        logger.info(f"510(k) search params: {params}")
        
        # 先尝试简单的查询
        data = self._make_request("/device/510k.json", params)
        
        # 如果失败，尝试更简单的查询
        if not data or 'results' not in data:
            logger.warning("First attempt failed, trying alternative query")
            
            # 尝试不同的查询方式
            alternative_searches = [
                f'product_code:{product_code}',  # 没有引号
                f'openfda.product_code:{product_code}',  # openfda字段
                f'product_code.exact:"{product_code}"'  # 精确匹配
            ]
            
            for alt_search in alternative_searches:
                logger.info(f"Trying alternative: {alt_search}")
                params['search'] = alt_search
                data = self._make_request("/device/510k.json", params)
                if data and 'results' in data and data['results']:
                    break
        
        if data and 'results' in data:
            formatted_records = self._format_510k_records(data['results'])
            
            return {
                'status': 'success',
                'product_code': product_code,
                'total': data.get('meta', {}).get('results', {}).get('total', len(formatted_records)),
                'last_updated': data.get('meta', {}).get('last_updated', ''),
                'records': formatted_records
            }
        
        # 如果没有结果，返回空数据而不是错误
        return {
            'status': 'success',
            'product_code': product_code,
            'total': 0,
            'last_updated': '',
            'records': []
        }
    
    def _format_510k_records(self, records: List[Dict]) -> List[Dict]:
        """Format 510(k) records for display"""
        formatted = []
        for record in records:
            # 安全地获取字段值
            openfda = record.get('openfda', {})
            
            formatted.append({
                'k_number': record.get('k_number', 'N/A'),
                'device_name': record.get('device_name', 'N/A'),
                'product_code': record.get('product_code', 'N/A'),
                'decision_date': record.get('decision_date', 'N/A'),
                'decision_code': record.get('decision_code', 'N/A'),
                'advisory_committee': record.get('advisory_committee', 'N/A'),
                'regulation_number': openfda.get('regulation_number', ['N/A'])[0] if openfda.get('regulation_number') else 'N/A',
                'applicant': record.get('applicant', 'N/A'),
                'date_received': record.get('date_received', 'N/A')
            })
        return formatted
    
    def get_adverse_events_stats(self, product_code: str = None) -> Dict:
        """Get adverse event statistics for a product code"""
        if not product_code:
            return {'status': 'error', 'message': 'No product code provided'}
        
        # 多个可能的字段名
        search_queries = [
            f'device.product_code:"{product_code}"',
            f'device.device_report_product_code:"{product_code}"',
            f'device.generic_name:"{product_code}"',
            f'product_code:"{product_code}"'
        ]
        
        result = {
            'status': 'success',
            'product_code': product_code,
            'total': 0,
            'by_event_type': [],
            'by_report_source': [],
            'by_year': []
        }
        
        # 尝试不同的查询
        for search in search_queries:
            logger.info(f"Trying adverse event search: {search}")
            
            # 获取总数
            params = {'search': search, 'limit': 1}
            data = self._make_request("/device/event.json", params)
            
            if data and 'results' in data:
                total = data.get('meta', {}).get('results', {}).get('total', 0)
                if total > 0:
                    result['total'] = total
                    
                    # 获取事件类型分布
                    params = {'search': search, 'count': 'event_type.exact', 'limit': 1000}
                    data_type = self._make_request("/device/event.json", params)
                    if data_type and 'results' in data_type:
                        result['by_event_type'] = data_type['results'][:10]
                    
                    # 获取报告来源分布
                    params = {'search': search, 'count': 'report_source_code.exact', 'limit': 1000}
                    data_source = self._make_request("/device/event.json", params)
                    if data_source and 'results' in data_source:
                        result['by_report_source'] = data_source['results'][:10]
                    
                    # 获取年度趋势
                    params = {'search': search, 'count': 'date_received', 'limit': 1000}
                    data_year = self._make_request("/device/event.json", params)
                    if data_year and 'results' in data_year:
                        result['by_year'] = self._format_yearly_data(data_year['results'])
                    
                    break  # 找到数据就停止
        
        return result
    
    def get_recall_stats(self, product_code: str = None) -> Dict:
        """Get recall statistics for a product code"""
        if not product_code:
            return {'status': 'error', 'message': 'No product code provided'}
        
        # 尝试不同的查询
        search_queries = [
            f'product_code:"{product_code}"',
            f'product_code:{product_code}',
            f'product_code.exact:"{product_code}"'
        ]
        
        result = {
            'status': 'success',
            'product_code': product_code,
            'total': 0,
            'by_classification': [],
            'by_status': [],
            'by_root_cause': []
        }
        
        for search in search_queries:
            logger.info(f"Trying recall search: {search}")
            
            # 获取总数
            params = {'search': search, 'limit': 1}
            data = self._make_request("/device/recall.json", params)
            
            if data and 'results' in data:
                total = data.get('meta', {}).get('results', {}).get('total', 0)
                if total > 0:
                    result['total'] = total
                    
                    # 获取分类分布
                    params = {'search': search, 'count': 'openfda.device_class.exact', 'limit': 1000}
                    data_class = self._make_request("/device/recall.json", params)
                    if data_class and 'results' in data_class:
                        result['by_classification'] = data_class['results'][:10]
                    
                    # 获取状态分布
                    params = {'search': search, 'count': 'recall_status.exact', 'limit': 1000}
                    data_status = self._make_request("/device/recall.json", params)
                    if data_status and 'results' in data_status:
                        result['by_status'] = data_status['results'][:10]
                    
                    # 获取根本原因分布
                    params = {'search': search, 'count': 'root_cause_description.exact', 'limit': 1000}
                    data_cause = self._make_request("/device/recall.json", params)
                    if data_cause and 'results' in data_cause:
                        result['by_root_cause'] = data_cause['results'][:10]
                    
                    break  # 找到数据就停止
        
        return result
    
    def _format_yearly_data(self, results: List[Dict]) -> List[Dict]:
        """Format time-series data by year"""
        yearly = {}
        for item in results:
            time_str = item.get('time', '')
            count = item.get('count', 0)
            
            if time_str and count > 0:
                try:
                    # 解析日期字符串 (格式: "2014-01-01")
                    year = time_str[:4]
                    if year and year.isdigit():
                        year_int = int(year)
                        if year_int not in yearly:
                            yearly[year_int] = 0
                        yearly[year_int] += count
                except (ValueError, IndexError) as e:
                    logger.warning(f"Could not parse time string '{time_str}': {e}")
                    continue
        
        # 按年份排序
        sorted_years = sorted(yearly.items())
        
        return [{'year': str(year), 'count': count} for year, count in sorted_years]
    
    def compare_products(self, product_codes: List[str]) -> Dict:
        """Compare two product codes across all metrics"""
        if len(product_codes) != 2:
            return {'status': 'error', 'message': 'Exactly two product codes required for comparison'}
        
        comparison = {
            'status': 'success',
            'product_codes': product_codes,
            'date_range': '2010-2025',
            'products': []
        }
        
        for code in product_codes:
            product_data = {
                'product_code': code,
                'adverse_events': 0,
                'recalls': 0,
                'latest_510k': None
            }
            
            # 获取不良事件数据
            ae_data = self.get_adverse_events_stats(code)
            if ae_data.get('status') == 'success':
                product_data['adverse_events'] = ae_data.get('total', 0)
            
            # 获取召回数据
            recall_data = self.get_recall_stats(code)
            if recall_data.get('status') == 'success':
                product_data['recalls'] = recall_data.get('total', 0)
            
            # 获取最新的510(k)
            k_data = self.get_510k_records(code, limit=1)
            if k_data.get('status') == 'success' and k_data.get('records'):
                product_data['latest_510k'] = k_data['records'][0].get('decision_date', 'N/A')
            
            comparison['products'].append(product_data)
        
        return comparison
    
    def test_connection(self) -> Dict:
        """测试API连接和基本查询"""
        test_cases = [
            {
                'endpoint': '/device/510k.json',
                'params': {'search': 'product_code:"GEI"', 'limit': 1},
                'description': '510(k) basic query'
            },
            {
                'endpoint': '/device/event.json',
                'params': {'search': 'device.product_code:"GEI"', 'limit': 1},
                'description': 'Adverse event basic query'
            },
            {
                'endpoint': '/device/recall.json',
                'params': {'search': 'product_code:"GEI"', 'limit': 1},
                'description': 'Recall basic query'
            }
        ]
        
        results = []
        for test in test_cases:
            try:
                data = self._make_request(test['endpoint'], test['params'])
                success = data is not None and 'results' in data
                results.append({
                    'test': test['description'],
                    'success': success,
                    'url': f"{self.base_url}{test['endpoint']}",
                    'params': test['params']
                })
            except Exception as e:
                results.append({
                    'test': test['description'],
                    'success': False,
                    'error': str(e)
                })
        
        return {'status': 'success', 'tests': results}
    
    def close(self):
        """Close the requests session"""
        if self.session:
            self.session.close()